

package com.jf.cloud.seckill.controller.app;

import cn.hutool.core.collection.CollectionUtil;
import com.jf.cloud.api.delivery.dto.CalculateAndGetDeliverInfoDTO;
import com.jf.cloud.api.delivery.feign.DeliveryFeignClient;
import com.jf.cloud.api.order.manager.ConfirmOrderManager;
import com.jf.cloud.api.order.manager.SubmitOrderManager;
import com.jf.cloud.api.product.manager.ShopCartAdapter;
import com.jf.cloud.api.product.manager.ShopCartItemAdapter;
import com.jf.cloud.common.constant.StatusEnum;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.order.constant.DeliveryType;
import com.jf.cloud.common.order.constant.OrderActivityType;
import com.jf.cloud.common.order.constant.OrderType;
import com.jf.cloud.common.order.util.OrderLangUtil;
import com.jf.cloud.common.order.vo.*;
import com.jf.cloud.common.response.ResponseEnum;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.rocketmq.config.RocketMqConstant;
import com.jf.cloud.common.security.AuthUserContext;
import com.jf.cloud.seckill.dto.app.SeckillOrderDTO;
import com.jf.cloud.seckill.dto.app.SubmitSeckillOrderDTO;
import com.jf.cloud.seckill.manager.SeckillCacheManager;
import com.jf.cloud.seckill.service.SeckillOrderService;
import com.jf.cloud.seckill.service.SeckillService;
import com.jf.cloud.seckill.service.SeckillSkuService;
import com.jf.cloud.seckill.vo.SeckillSkuVO;
import com.jf.cloud.seckill.vo.SeckillVO;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;


/**
 * 秒杀信息
 *
 * @author zz
 * @date 2021-04-19 09:36:59
 */
@RestController
@RequestMapping("/seckill_order" )
@Tag(name = "秒杀订单接口")
public class SeckillOrderController {

    @Autowired
    private SeckillService seckillService;
    @Autowired
    private SeckillSkuService seckillSkuService;
    @Autowired
    private SeckillCacheManager seckillCacheManager;
    @Autowired
    private ConfirmOrderManager confirmOrderManager;
    @Autowired
    private ShopCartAdapter shopCartAdapter;
    @Autowired
    private ShopCartItemAdapter shopCartItemAdapter;
    @Autowired
    private DeliveryFeignClient deliveryFeignClient;
    @Autowired
    private SubmitOrderManager submitOrderManager;
    @Autowired
    private SeckillOrderService seckillOrderService;
    @Autowired
    private RocketMQTemplate seckillOrderCreateTemplate;
    @Operation(summary = "获取秒杀订单路径")
    @GetMapping(value="/order_path")
    public ServerResponseEntity<String> getOrderPath(Long spuId) {
        Long userId = AuthUserContext.get().getUserId();
        SeckillVO seckill = seckillService.getBySpuId(spuId);
        // 前端看到这个状态码的时候，不用渲染活动页面了
        if (seckill == null || !Objects.equals(seckill.getStatus(), StatusEnum.ENABLE.value()) || seckill.getEndTime().getTime() < System.currentTimeMillis()) {
            return ServerResponseEntity.showFailMsg("活动已结束");
        }
        if (seckill.getStartTime().getTime() > System.currentTimeMillis()) {
            return ServerResponseEntity.showFailMsg("活动尚未开始");
        }
        String orderPath = seckillCacheManager.createOrderPath(userId + spuId);

        return ServerResponseEntity.success(orderPath);
    }


    @Operation(summary = "确认订单")
    @PostMapping(value="/{orderPath}/confirm")
    public ServerResponseEntity<ShopCartOrderMergerVO> confirm(@PathVariable("orderPath") String orderPath, @Valid @RequestBody SeckillOrderDTO orderParam) {

        Long userId = AuthUserContext.get().getUserId();

        Long spuId = orderParam.getShopCartItem().getSpuId();
        seckillCacheManager.checkOrderPath(userId + spuId,orderPath);

        SeckillSkuVO appSeckillSkuVO = seckillSkuService.getBySeckillSkuId(orderParam.getSeckillSkuId());
        if (appSeckillSkuVO == null || !Objects.equals(orderParam.getShopCartItem().getSkuId(), appSeckillSkuVO.getSkuId())) {
            throw new LuckException("sku 信息有误");
        }

        List<ShopCartItemVO> shopCartItemsDb = shopCartItemAdapter.conversionShopCartItem(orderParam.getShopCartItem(), appSeckillSkuVO.getSeckillPrice(), userId, orderParam.getAddrId());
        // 检查地址
        confirmOrderManager.checkAddr(shopCartItemsDb,userId,orderParam.getAddrId());
        // 将要返回给前端的完整的订单信息
        ShopCartOrderMergerVO shopCartOrderMerger = new ShopCartOrderMergerVO();
        shopCartOrderMerger.setDvyTypes(orderParam.getDvyTypes());
        shopCartOrderMerger.setOrderType(OrderType.SECKILL);
        shopCartOrderMerger.setSeckillSkuId(orderParam.getSeckillSkuId());
        shopCartOrderMerger.setActivityId(appSeckillSkuVO.getSeckillId());
        shopCartOrderMerger.setActivityType(OrderActivityType.SECKILL.value());

        // 筛选过滤掉不同配送的商品
        List<ShopCartItemVO> shopCartItems = confirmOrderManager.filterShopItemsByType(shopCartOrderMerger,shopCartItemsDb);
        OrderLangUtil.shopCartItemList(shopCartItems);
        // 无法配送的商品添加商品详细和店铺详细
        shopCartAdapter.setFilterShopItemsLong(shopCartOrderMerger);
        // 该商品不满足任何的配送方式
        if (CollectionUtil.isEmpty(shopCartItems)) {
            // 设置用户地址
            UserDeliveryInfoVO userDeliveryInfoVO = deliveryFeignClient.calculateAndGetDeliverInfo(new CalculateAndGetDeliverInfoDTO(orderParam.getAddrId(), orderParam.getStationId(), shopCartItems, orderParam.getDvyTypes())).getData();
            shopCartOrderMerger.setUserAddr(userDeliveryInfoVO.getUserAddr());
            return ServerResponseEntity.success(shopCartOrderMerger);
        }
        // 商品类别 0.实物商品 1. 虚拟商品
        int mold = 0;
        if (shopCartItemsDb.stream().filter(shopCartItemDto -> Objects.nonNull(shopCartItemDto.getSpuMold()) && shopCartItemDto.getSpuMold() == 1).count() == shopCartItemsDb.size()) {
            // 订单项中的所有商品都为虚拟商品时，才是虚拟订单
            mold = 1;
            shopCartOrderMerger.getDvyTypes().forEach(s->s.setDvyType(DeliveryType.NOT_DELIVERY.value()));
        }
        shopCartOrderMerger.setSpuMold(mold);
        // 购物车
        List<ShopCartVO> shopCarts = shopCartAdapter.conversionShopCart(shopCartItems);
        // 计算运费，获取用户地址，自提信息
        ServerResponseEntity<UserDeliveryInfoVO> userDeliveryInfoResponseEntity = deliveryFeignClient.calculateAndGetDeliverInfo(new CalculateAndGetDeliverInfoDTO(orderParam.getAddrId(), orderParam.getStationId(), shopCartItems, orderParam.getDvyTypes()));

        // 当算完一遍店铺的各种满减活动时，重算一遍订单金额
        confirmOrderManager.recalculateAmountWhenFinishingCalculateShop(shopCartOrderMerger, shopCarts, userDeliveryInfoResponseEntity.getData());

        // 结束平台优惠的计算之后，还要重算一遍金额
        confirmOrderManager.recalculateAmountWhenFinishingCalculatePlatform(shopCartOrderMerger, userDeliveryInfoResponseEntity.getData());

        shopCartOrderMerger.getShopCartOrders().forEach(shopCartOrderVO -> shopCartOrderVO.setOrderType(OrderType.SECKILL.value()));

        // 计算平台佣金-跟订单其他金额是独立的，可以单独计算
        confirmOrderManager.confirmPlatformCommission(shopCartOrderMerger);

        // 缓存计算新
        confirmOrderManager.cacheCalculatedInfo(userId, shopCartOrderMerger);
        List<ShopCartOrderVO> shopCartOrders = shopCartOrderMerger.getShopCartOrders();
        Iterator<ShopCartOrderVO> shopCartOrderVOIterator = shopCartOrders.iterator();
        // 移除没有商品项的店铺的订单信息
        while (shopCartOrderVOIterator.hasNext()){
            ShopCartOrderVO shopCartOrderVO = shopCartOrderVOIterator.next();
            if (shopCartOrderVO.getShopCartItemDiscounts().size() == 0){
                shopCartOrderVOIterator.remove();
            }
        }
        return ServerResponseEntity.success(shopCartOrderMerger);
    }

    /**
     * 购物车/立即购买  提交订单,根据店铺拆单
     */
    @PostMapping("/{orderPath}/submit")
    @Operation(summary = "提交订单" , description = "提交之后返回WebSocket路径，请求对应的WebSocket路径，开始等待响应")
    public ServerResponseEntity<List<Long>> submitOrders(@PathVariable("orderPath") String orderPath, @Valid @RequestBody SubmitSeckillOrderDTO submitOrderParam) {
        Long userId = AuthUserContext.get().getUserId();



        // 在这里面已经生成了订单id了
        ServerResponseEntity<ShopCartOrderMergerVO> checkResult = submitOrderManager.checkSubmitInfo(submitOrderParam, userId);
        if (!checkResult.isSuccess()) {
            return ServerResponseEntity.transform(checkResult);
        }
        ShopCartOrderMergerVO mergerOrder = checkResult.getData();
        mergerOrder.setUserId(userId);
        ShopCartOrderVO shopCartOrderVO = mergerOrder.getShopCartOrders().get(0);
        ShopCartItemVO shopCartItemVO = shopCartOrderVO.getShopCartItemDiscounts().get(0).getShopCartItems().get(0);

        // 验证订单路径
        seckillCacheManager.checkOrderPath(userId + shopCartItemVO.getSpuId(),orderPath);

        // 秒杀活动信息（来自缓存）
        SeckillVO seckill = seckillService.getBySpuId(shopCartItemVO.getSpuId());

        // 前端看到这个状态码的时候，不用渲染活动页面了
        if (seckill == null || !Objects.equals(seckill.getStatus(), StatusEnum.ENABLE.value()) || seckill.getEndTime().getTime() < System.currentTimeMillis()) {
            return ServerResponseEntity.showFailMsg("活动已结束");
        }

        // 判断之前秒杀的商品有没有超过限制，-1表示商品不限制秒杀数量
        if (seckill.getMaxNum() != -1 && seckill.getMaxNum() < shopCartItemVO.getCount()) {
            return ServerResponseEntity.showFailMsg("超过购买限制");
        }
        // 判断之前秒杀的商品有没有超过限制，-1表示商品不限制秒杀数量
        boolean isOverNum = seckillOrderService.checkOrderSpuNum(seckill, mergerOrder.getUserId(), shopCartItemVO.getCount());
        if (!isOverNum) {
            return ServerResponseEntity.showFailMsg("超过购买限制");
        }

        mergerOrder.setActivityId(seckill.getSeckillId());
        mergerOrder.setActivityType(OrderActivityType.SECKILL.value());

        // 为啥要事务消息，为了确保扣减秒杀的库存后，订单能够创建成功，因为redis和mysql是不同的异构数据源
        // SeckillOrderCreateTransactionListener SeckillOrderCreateConsumer
        TransactionSendResult transactionSendResult = seckillOrderCreateTemplate.sendMessageInTransaction(RocketMqConstant.SECKILL_ORDER_CREATE_TOPIC, new GenericMessage<>(mergerOrder), shopCartItemVO);

        if (!Objects.equals(transactionSendResult.getLocalTransactionState(), LocalTransactionState.COMMIT_MESSAGE)) {
            return ServerResponseEntity.showFailMsg("库存不足，请稍后再试");
        }

        return ServerResponseEntity.success(Collections.singletonList(shopCartOrderVO.getOrderId()));
    }

}
